﻿#region Copyright

//  ======================================================
//      Copyright (c) 2011 Toulr All rights reserved.
//     
//      The use and distribution terms for this software are contained in the file
//      named license.txt, which can be found in the root of this distribution.
//      By using this software in any fashion, you are agreeing to be bound by the
//      terms of this license.
//     
//     You must not remove this notice, or any other, from this software.
//  ======================================================

#endregion

#region Using Namespaces

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.Entity.Validation;
using System.Linq;
using Toulr.Domains;
using Toulr.Domains.Account;
using Toulr.Domains.Business;
using Toulr.Models;
using Toulr.Models.Account;
using Toulr.Services;
using Toulr.Util.Logging;
using Toulr.Util.Net.Email;
using Toulr.Util.Text;
using System.Text;
using Toulr.Util.Security;

#endregion

namespace Toulr.Core.Services
{
    public class UserContextService : ApplicationContextService, IUserContextService
    {
        private static Repository<User> _repository = new Repository<User>();
        private static readonly ILogger _logger = LogHelper.LogFactoy.Create("UserContextService");

        #region IUserContextService Members

        public ActionResult<bool> Register(RegisterModel registerModel)
        {
            var result = new ActionResult<bool>(1, "", false);
            try
            {
                _repository = new Repository<User>();
                //校验输入信息是否有效
                if (!String.IsNullOrEmpty(registerModel.Pwd) && !String.IsNullOrEmpty(registerModel.Email))
                {
                    if (EmailRegistered(registerModel.Email).Result)
                    {
                        //如果电子邮件已经注册过
                        return new ActionResult<bool>(1, GetMessageString("ERROR_EMAIL_REGISTED"), false);
                    }

                    var user = new User { SaltValue = DateTime.Now.Millisecond, Email = registerModel.Email };
                    user.Password = Toulr.Util.Text.Encoding.Md5(registerModel.Pwd + user.SaltValue);
                    user.NickName = registerModel.Email.Split(new string[] { "@" }, StringSplitOptions.None)[0];
                    user.RegisterTime = DateTime.Now;
                    user.FullName = registerModel.RealName;

                    user.EmailVerified = true;
                    user.RoleId = _repository.DbContext.UserRoles.First(r => r.Id == 1).Id;

                    //todo 没有搞清楚什么意思，所有用户都接收消息？ 重构时先注掉吧 hyyu 20110525
                    //user.UserNoticeConfig = new UserNoticeConfig { RecieveMessageNotice = true };
                    user.RoleId = _repository.DbContext.UserRoles.First(r => r.Id == 1).Id;

                    _repository.Add(user);
                    result = new ActionResult<bool>(0, GetMessageString("MSG_REGISTER_SUCCESSFUL"), true);
                }
            }
            catch (DbEntityValidationException ex)
            {
                foreach (var dbEntityValidationResult in ex.EntityValidationErrors)
                {
                    _logger.Error(dbEntityValidationResult.ValidationErrors.FirstOrDefault().PropertyName +
                                  ":" + dbEntityValidationResult.ValidationErrors.FirstOrDefault().ErrorMessage);
                }
            }
            catch (DbException ex)
            {
                _logger.Error(ex.Message, ex);
            }
            return result;
        }
        public ActionResult<bool> ForgetPassword(string email)
        {
            _repository = new Repository<User>();
            //基于输入对象计算密码散列
            var u = GetUser(email);
            if (u == null)
                return new ActionResult<bool>(1, GetMessageString("ERROR_USER_DOES_NOT_EXIST"), false);

            string newPwd = PasswordHelper.GenerateRandomPassword(8);

            u.Password = Toulr.Util.Text.Encoding.Md5(newPwd + u.SaltValue);
            _repository.Update(u);

            StringBuilder bodyHtml = new StringBuilder();

            bodyHtml.AppendLine("尊敬的偷乐网用户" + email + ", 您好<br>");
            bodyHtml.AppendLine("&nbsp;&nbsp;&nbsp;&nbsp;您的新密码为 <br>" + newPwd);
            try
            {
                var message = new Message(Resource.Resource.Email_Source,
                    email,
                    Resource.Resource.RegisterMail_Title,
                    bodyHtml.ToString());

                Utility.SendMail(message);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);
                return new ActionResult<bool>(2, GetMessageString("ERROR_VERIFICATION_MAIL_SEND_FAILS"), false);
            }

            return new ActionResult<bool>(0, GetMessageString("MSG_CHANGED_SUCCESSFULLY"), true);
        }

        public ActionResult<bool> ChanagePassword(ChanagePasswordModel chanagePasswordModel)
        {
            //判断输入模型是否合法ERROR_INFORMATION_IS_INCOMPLETE
            if (chanagePasswordModel == null || String.IsNullOrEmpty(chanagePasswordModel.Email) ||
                String.IsNullOrEmpty(chanagePasswordModel.OldPassword))
                return new ActionResult<bool>(1, GetMessageString("ERROR_INFORMATION_IS_INCOMPLETE"), false);
            //基于输入对象计算密码散列
            var u = GetUser(chanagePasswordModel.Email);
            if (u == null)
                return new ActionResult<bool>(1, GetMessageString("ERROR_USER_DOES_NOT_EXIST"), false);

            if (u.Password == Toulr.Util.Text.Encoding.Md5(chanagePasswordModel.OldPassword + u.SaltValue))
            {
                u.Password = Toulr.Util.Text.Encoding.Md5(chanagePasswordModel.NewPassword + u.SaltValue);
                _repository.Update(u);

                return new ActionResult<bool>(0, GetMessageString("MSG_CHANGED_SUCCESSFULLY"), true);
            }
            return new ActionResult<bool>(1, GetMessageString("ERROR_USER_NAME_OR_PASSWORD_ERROR"), false);
        }

        ActionResult<User> IUserContextService.Modify(ModifyModel modifyModel)
        {
            _repository.Update(modifyModel.UserToModify);
            return new ActionResult<User>(0, GetMessageString("MSG_USER_INFORMATION_MODIFIED"), modifyModel.UserToModify);
        }

        ActionResult<bool> IUserContextService.VerifyEmail(string verifyCode)
        {
            String result = Toulr.Util.Text.Encoding.Rc2Decrypt(verifyCode, Resource.Resource.KEY, Resource.Resource.IV);
            String email = result.Split(new[] { "$" }, StringSplitOptions.RemoveEmptyEntries)[0];
            if (EmailRegistered(email).Result) //如果在当前注册用户内包括当前EMAIL
            {
                User user = GetUser(email);
                user.EmailVerified = true;
                _repository.Update(user);//
                return new ActionResult<bool>(0, GetMessageString("MSG_EMAIL_VEIFIED"), true);
            }
            return new ActionResult<bool>(1, GetMessageString("ERROR_EMAIL_VEIFIED_FAILS"), false);
        }

        public ActionResult<bool> SendVerifyMail(string email, string baseUrl)
        {
            string emailIdentifyCode = Toulr.Util.Text.Encoding.Rc2EncryptForUrl(email,
                Resource.Resource.KEY, Resource.Resource.IV);

            string timeIdentifyCode = Toulr.Util.Text.Encoding.Rc2EncryptForUrl(DateTime.Now.ToString("yyyy/MM/dd HH:mm"),
                Resource.Resource.KEY, Resource.Resource.IV);

            StringBuilder bodyHtml = new StringBuilder();

            bodyHtml.AppendLine("请点击下面的网址确认您在<a href='" + baseUrl + "' >偷乐网</a>注册的Email地址。24小时内激活有效！<br>");
            bodyHtml.AppendLine(baseUrl + "/account/Reg2.aspx?i=" + emailIdentifyCode + "&t=" + timeIdentifyCode);
            try
            {
                var message = new Message(Resource.Resource.Email_Source,
                    email,
                    Resource.Resource.RegisterMail_Title,
                    bodyHtml.ToString());

                Utility.SendMail(message);//
                return new ActionResult<bool>(0, GetMessageString("MSG_VERIFICATION_MAIL_SENT"), true);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);
                return new ActionResult<bool>(1, GetMessageString("ERROR_VERIFICATION_MAIL_SEND_FAILS"), false);
            }
        }
        /// <summary>
        /// Verifies the email link.
        /// </summary>
        /// <param name="emailIdentifyCode">The email identify code.</param>
        /// <param name="timeIdentifyCode">The time identify code.</param>
        /// <returns></returns>
        /// <Author>Tecky Lee</Author>
        /// <Date>2011/5/24 19:48</Date>
        public ActionResult<string> VerifyEmailLink(string emailIdentifyCode, string timeIdentifyCode)
        {
            try
            {
                if (string.IsNullOrEmpty(emailIdentifyCode) || string.IsNullOrEmpty(timeIdentifyCode))
                {
                    return new ActionResult<string>(-2, "该电子邮件地址激活链接不正确！", string.Empty);
                }

                string email = Toulr.Util.Text.Encoding.Rc2DecryptForUrl(emailIdentifyCode, Resource.Resource.KEY, Resource.Resource.IV);
                string timeString = Toulr.Util.Text.Encoding.Rc2DecryptForUrl(timeIdentifyCode, Resource.Resource.KEY, Resource.Resource.IV);

                if (((TimeSpan)(DateTime.Now - DateTime.Parse(timeString))).TotalHours > 24)
                {
                    return new ActionResult<string>(-3, "该电子邮件地址激活链接已经超过24小时有效期！", email);
                }

                if (string.IsNullOrEmpty(email))
                {
                    return new ActionResult<string>(-2, "该电子邮件地址激活链接不正确！", string.Empty);
                }

                if (EmailRegistered(email).Result)
                {
                    return new ActionResult<string>(-4, "该电子邮箱地址已经被注册！", email);
                }
                return new ActionResult<string>(0, "电子邮箱地址通过验证！", email);
            }
            catch (System.Exception ex)
            {
                _logger.Error("来自用户邮箱的邮箱地址确认连接无法正常解密！ ", ex);

                return new ActionResult<string>(-1, "无法正确识别您的Http请求！", string.Empty);
            }
        }
        public ActionResult<string> SendVerifyCode(string phone)
        {
            String code = Toulr.Util.Text.Encoding.Hex(Toulr.Util.Text.Encoding.Md5(phone + DateTime.Now.Millisecond)).Substring(0, 6).Replace("-", "");
            return new ActionResult<String>(1, GetMessageString("MSG_VERIFICATION_CODE_SENT"), code);//
        }


        public ActionResult<bool> VerifyMobilePhone(string email, string verifyCode)
        {
            _logger.Error(GetMessageString("MSG_VERIFICATION_CODE_SENT"));
            _logger.Error(GetMessageString("ERROR_VERIFICATION_MAIL_SEND_FAILS"));
            return null;
        }

        public ActionResult<bool> DeleteUser(string email)
        {
            _repository = new Repository<User>();
            User user = GetUser(email);
            if (user != null)
            {
                _repository.Delete(user);//
                return new ActionResult<bool>(0, GetMessageString("MSG_USER_DELETE_SUCCESSFUL"), true);
            }
            return new ActionResult<bool>(1, GetMessageString("ERROR_USER_DOES_NOT_EXIST"), false);
        }

        public ActionResult<bool> EmailRegistered(string email)
        {
            var u = GetUser(email);
            if (u != null && !String.IsNullOrEmpty(u.Email))
                return new ActionResult<bool>(0, GetMessageString("ERROR_EMAIL_REGISTED"), true);
            return new ActionResult<bool>(0, GetMessageString("ERROR_EMAIL_REGISTED"), false);
        }

        public Repository<User> Repository
        {
            get { return _repository; }
            set { }
        }

        /// <summary>
        ///   根据提供的信息进行登录校验
        /// </summary>
        /// <param name = "loginModel">用户登录模型.</param>
        /// <returns></returns>
        /// Author: James Cheung
        /// MachineName: JAMESCHEUNG-PC
        /// DateTime: 2011/5/10 23:01
        public ActionResult<User> Login(LoginModel loginModel)
        {
            //判断输入模型是否合法
            if (loginModel == null || String.IsNullOrEmpty(loginModel.Email) ||
                String.IsNullOrEmpty(loginModel.Password))//
                return new ActionResult<User>(1, GetMessageString("ERROR_LOGIN_INFO_MUST_COMPLETED"), null);
            //基于输入对象计算密码散列
            var u = GetUser(loginModel.Email);
            if (u == null)//
                return new ActionResult<User>(1, GetMessageString("ERROR_USER_DOES_NOT_EXIST"), u);
            if (u.EmailVerified != true)//
                return new ActionResult<User>(1, GetMessageString("ERROR_EMAIL_NOT_VERIFIED"), u);
            if (u.Password == Toulr.Util.Text.Encoding.Md5(loginModel.Password + u.SaltValue))
                return new ActionResult<User>(0, GetMessageString("MSG_LOGIN_SUCCESSFUL"), u);//
            return new ActionResult<User>(1, GetMessageString("ERROR_USER_NAME_OR_PASSWORD_ERROR"), u);
        }

        public ActionResult<List<Messages>> GetMessages(int userId)
        {
            var msg = from m in _repository.DbContext.Messageses
                      where m.RecieveUser == userId
                      orderby m.SentTime descending
                      select m;//
            return new ActionResult<List<Messages>>(0, GetMessageString("MSG_OPERATION_SUCCESSFUL"), msg.ToList());
        }

        public ActionResult<List<Messages>> GetSentMessages(int userId)
        {
            var msg = from m in _repository.DbContext.Messageses
                      where m.SentUserId == userId
                      orderby m.SentTime descending
                      select m;
            return new ActionResult<List<Messages>>(0, GetMessageString("MSG_OPERATION_SUCCESSFUL"), msg.ToList());
        }

        /// <summary>
        ///   发送消息
        /// </summary>
        /// <returns></returns>
        /// Author: James Cheung
        /// MachineName: JAMESCHEUNG-PC
        /// DateTime: 2011/5/13 21:49
        public ActionResult<bool> SendMessage(string msg, int fromUser, int toUser)
        {
            User from = GetUser(fromUser);
            User to = GetUser(toUser);
            if (from == null || to == null)
                return new ActionResult<bool>(1, GetMessageString("ERROR_USER_DOES_NOT_EXIST"), false);
            _repository.DbContext.Messageses.Add(new Messages
                                                     {
                                                         Message = msg,
                                                         Readed = false,
                                                         RecieveUser = GetUser(toUser).Uid,
                                                         SentUserId = GetUser(fromUser).Uid,
                                                         SentTime = DateTime.Now
                                                     });

            UserNoticeConfig config = _repository.DbContext.UserNoticeConfigs.Find(to.UserNoticeConfigId);
            if (config.RecieveMessageNotice) //如果需要邮件通知
            {
                String msgHtml = String.Format(GetMessageString("MSG_RECIEVE_MSG_EMAIL_ALERTS"), from.NickName, to.NickName, msg);
                var mail = new Message("", to.Email, String.Format(GetMessageString("MSG_RECIEVE_MSG_EMAIL_ALERTS_TITLE"), from.NickName), msgHtml);
                Utility.SendMail(mail);
            }
            _repository.DbContext.SaveChanges();
            return new ActionResult<bool>(0, GetMessageString("MSG_MSG_SEND_SUCCESSFUL"), true);
        }

        public ActionResult<List<Friends>> GetFriends(int userId)
        {
            var friendses = from m in _repository.DbContext.Friends
                            where (m.OriginalUser.Uid == userId || m.TargetUser.Uid == userId) && m.Status.Id != 3
                            orderby m.TargetUser.NickName descending
                            select m;
            return new ActionResult<List<Friends>>(0, GetMessageString("MSG_OPERATION_SUCCESSFUL"), friendses.ToList());
        }

        public ActionResult<bool> RemoveFriends(IList<int> friendses)
        {
            try
            {
                foreach (var i in friendses)
                {
                    var friend = _repository.DbContext.Friends.First(r => r.Id == i);
                    if (friend != null)
                    {
                        friend.StatusId = _repository.DbContext.FriendStatus.First(r => r.Id == 3).Id;
                    }
                    _repository.DbContext.SaveChanges();
                }//
                return new ActionResult<bool>(0, GetMessageString("MSG_DELETE_SUCCESSFUL"), true);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);
                return new ActionResult<bool>(1, GetMessageString("ERROR_UNKNOW"), false);
            }
        }

        public ActionResult<bool> AddFriend(int fromUser, int toUser, string requestMsg)
        {
            try
            {
                User from = GetUser(fromUser);
                User to = GetUser(toUser);
                if (from == null || to == null)//
                    return new ActionResult<bool>(1, GetMessageString("ERROR_USER_DOES_NOT_EXIST"), false);
                //TODO:尚未检查是否已经存在好友关系了
                _repository.DbContext.Friends.Add(new Friends
                                                      {
                                                          OriginalUserId = from.Uid,
                                                          TargetUserId = to.Uid,
                                                          RequestMessage = requestMsg,
                                                          StatusId =
                                                              _repository.DbContext.FriendStatus.First(r => r.Id == 0).Id
                                                      });
                //邮件通知用户有人加为好友,
                var message = new Message("", to.Email, String.Format(GetMessageString("MSG_ADD_FRIEND_MAIL_TITLE"), from.NickName),
                                       String.Format(GetMessageString("MSG_ADD_FRIEND_MAIL_BODY"), from.NickName));
                Utility.SendMail(message);//
                return new ActionResult<bool>(0, GetMessageString("MSG_OPERATION_SUCCESSFUL"), true);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);//
                return new ActionResult<bool>(1, GetMessageString("ERROR_UNKNOW"), false);
            }
        }

        public ActionResult<bool> ConfirmFriend(int friendId)
        {
            try
            {
                _repository.DbContext.Friends.First(r => r.Id == friendId).StatusId =
                    _repository.DbContext.FriendStatus.First(r => r.Id == 1).Id;
                _repository.DbContext.SaveChanges();
                //
                return new ActionResult<bool>(0, GetMessageString("MSG_OPERATION_SUCCESSFUL"), true);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);//
                return new ActionResult<bool>(1, GetMessageString("ERROR_UNKNOW"), false);
            }
        }

        public ActionResult<bool> RejectFriend(int friendId)
        {
            try
            {
                _repository.DbContext.Friends.First(r => r.Id == friendId).StatusId =
                    _repository.DbContext.FriendStatus.First(r => r.Id == 2).Id;
                _repository.DbContext.SaveChanges();
                //
                return new ActionResult<bool>(0, GetMessageString("MSG_OPERATION_SUCCESSFUL"), true);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);//
                return new ActionResult<bool>(1, GetMessageString("ERROR_UNKNOW"), false);
            }
        }

        /// <summary>
        ///   获取用户账单信息
        /// </summary>
        /// <param name = "uid"></param>
        /// <returns></returns>
        /// Author: James Cheung
        /// MachineName: JAMESCHEUNG-PC
        /// DateTime: 2011/5/14 14:00
        public ActionResult<List<Bill>> GetBillHistory(int uid)
        {
            try
            {
                var bills = from m in _repository.DbContext.Bills
                            where m.PayUser.Uid == uid
                            orderby m.PayTime descending
                            select m;

                //
                return new ActionResult<List<Bill>>(0, GetMessageString("MSG_OPERATION_SUCCESSFUL"), bills.ToList());
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);//
                return new ActionResult<List<Bill>>(1, GetMessageString("ERROR_UNKNOW"), null);
            }
        }

        #endregion

        /// <summary>
        ///   获取指定Email对应的用户对象
        /// </summary>
        /// <param name = "uid"></param>
        /// <returns></returns>
        public static User GetUser(int uid)
        {
            try
            {
                return _repository.DbContext.Users.First(r => r.Uid == uid);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);
                return null;
            }
        }

        /// <summary>
        ///   获取指定Email对应的用户对象
        /// </summary>
        /// <param name = "email"></param>
        /// <returns></returns>
        private User GetUser(String email)
        {
            try
            {
                return _repository.DbContext.Users.First(r => r.Email == email);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message + ":" + email + "\n", ex);
                return null;
            }
        }

        const string cookieSpliter = "$%%$";
        public ActionResult<string> EncodeUserInfoForCookie(string email, string pwd)
        {
            try
            {
                string emailEncoded = Toulr.Util.Text.Encoding.Rc2Encrypt(email, Resource.Resource.KEY, Resource.Resource.IV);
                string pwdEncoded = Toulr.Util.Text.Encoding.Rc2Encrypt(pwd, Resource.Resource.KEY, Resource.Resource.IV);

                return new ActionResult<string>(0, "Success", emailEncoded + cookieSpliter + pwdEncoded);
            }
            catch (System.Exception ex)
            {
                _logger.Error(ex.Message + ":" + email + "\n", ex);
                return new ActionResult<string>(-1, "Failed", null);
            }
        }

        public ActionResult<User> LoginWithCookieIndentyString(string cookieUserInfo)
        {
            try
            {
                if (!cookieUserInfo.Contains(cookieSpliter))
                {
                    return new ActionResult<User>(-1, "Cookie无效", null);
                }
                string[] arrInfo = cookieUserInfo.Split(new string[] { cookieSpliter }, StringSplitOptions.RemoveEmptyEntries);
                if (arrInfo.Length != 2)
                {
                    return new ActionResult<User>(-1, "Cookie无效", null);
                }
                string email = Toulr.Util.Text.Encoding.Rc2Decrypt(arrInfo[0], Resource.Resource.KEY, Resource.Resource.IV);
                string pwd = Toulr.Util.Text.Encoding.Rc2Decrypt(arrInfo[1], Resource.Resource.KEY, Resource.Resource.IV); ;

                LoginModel model = new LoginModel() { Email = email, Password = pwd };
                return Login(model);
            }
            catch (System.Exception ex)
            {
                _logger.Error(ex.ToString());
                return new ActionResult<User>(-1, "Cookie无效", null);
            }
        }
    }
}